home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 4
/
Apprentice-Release4.iso
/
Source Code
/
Libraries
/
KPlib 1.3.5
/
KPBag.h
< prev
next >
Wrap
Text File
|
1995-12-17
|
17KB
|
615 lines
// A module of KPlib v1.3.5.
// Written by Keith Pomakis during the summer of 1994.
// Released to the public domain on October 10, 1994.
#ifndef KP_BAG_DEFINED
#define KP_BAG_DEFINED
#include <stdlib.h>
#include "KPbasic.h"
#include "KPList.h"
// Assumes Element has a default constructor, operator=(), operator==(),
// and operator<(). Note that operator<() must place a total ordering on
// the Elements.
// KPBag<T>::operator<() places a total ordering on all KPBag<T> elements,
// so that KPSet<KPBag<T> > is possible.
template <class Element>
class KPBag {
public:
KPBag();
KPBag(const KPBag<Element> &bag);
KPBag(const KPList<Element> &list);
KPBag(const Element &element, int count=1);
~KPBag();
operator KPList<Element>() const;
KPBag<Element> operator+(const KPBag<Element> &bag) const;
KPBag<Element> operator+(const Element &element) const;
KPBag<Element> &operator+=(const KPBag<Element> &bag);
KPBag<Element> &operator+=(const Element &element);
KPBag<Element> &add(const KPBag<Element> &bag);
KPBag<Element> &add(const Element &element, int num=1);
// It is illegal to call the following functions unless the elements
// are there to be removed! If unsure, call contains() first.
KPBag<Element> operator-(const KPBag<Element> &bag) const;
KPBag<Element> operator-(const Element &element) const;
KPBag<Element> &operator-=(const KPBag<Element> &bag);
KPBag<Element> &operator-=(const Element &element);
KPBag<Element> &remove(const KPBag<Element> &bag);
KPBag<Element> &remove(const Element &element, int num=1);
KPBag<Element> &remove_all(const Element &element);
// Miscellaneous
bool operator==(const KPBag<Element> &bag) const;
bool operator!=(const KPBag<Element> &bag) const;
bool operator<(const KPBag<Element> &bag) const;
KPBag<Element> &operator=(const KPBag<Element> &bag);
KPBag<Element> &operator=(const Element &element);
KPBag<Element> &operator=(const KPList<Element> &list);
KPList<Element> list() const;
KPList<Element> unique_list() const;
int size() const; // Total number of elements.
int unique_size() const; // Total number of unique elements.
bool is_empty() const;
bool contains(const KPBag<Element> &bag) const;
bool contains(const Element &element, int num=1) const;
int occurrences_of(const Element &element) const;
Element retrieve(); // Returns and removes an element.
KPBag<Element> &clear();
protected:
class Slot {
public:
Element my_element;
int my_count;
public:
Slot(): my_count(0)
{ /* do nothing */ }
Slot(const Slot &slot): my_count(slot.my_count)
{ my_element = slot.my_element; }
Slot(const Element &element, int num): my_count(num)
{ my_element = element; }
void operator=(const Slot &slot)
{ my_element = slot.my_element; my_count = slot.my_count; }
};
KPList<KPBag<Element>::Slot> my_list;
};
/****************************************************************************/
template <class Element>
inline
KPBag<Element>::KPBag(): my_list()
{ /* do nothing */ }
/****************************************************************************/
template <class Element>
inline
KPBag<Element>::KPBag(const KPBag<Element> &bag): my_list(bag.my_list)
{ /* do nothing */ }
/****************************************************************************/
template <class Element>
inline
KPBag<Element>::KPBag(const KPList<Element> &list)
{
*this = list;
}
/****************************************************************************/
template <class Element>
inline
KPBag<Element>::KPBag(const Element &element, int count): my_list()
{
if (count < 0) {
cerr << "KPBag - negative count\n";
exit(EXIT_FAILURE);
}
else if (count > 0) {
KPBag<Element>::Slot slot(element, count);
my_list = slot;
}
}
/****************************************************************************/
template <class Element>
inline
KPBag<Element>::~KPBag()
{
my_list.clear();
}
/****************************************************************************/
template <class Element>
KPBag<Element>::operator KPList<Element>() const
{
KPList<Element> list;
KPReadOnlyIterator<KPBag<Element>::Slot> iter(my_list);
FOREACH (iter)
for (register int i=0; i<iter->my_count; i++)
list.add_to_tail(iter->my_element);
return list;
}
/****************************************************************************/
template <class Element>
inline KPBag<Element>
KPBag<Element>::operator+(const KPBag<Element> &bag) const
{
KPBag<Element> new_bag(*this);
new_bag += bag;
return new_bag;
}
/****************************************************************************/
template <class Element>
inline KPBag<Element>
KPBag<Element>::operator+(const Element &element) const
{
KPBag<Element> new_bag(*this);
new_bag += element;
return new_bag;
}
/****************************************************************************/
template <class Element>
inline KPBag<Element> &
KPBag<Element>::operator+=(const KPBag<Element> &bag)
{
return add(bag);
}
/****************************************************************************/
template <class Element>
inline KPBag<Element> &
KPBag<Element>::operator+=(const Element &element)
{
return add(element, 1);
}
/****************************************************************************/
template <class Element>
KPBag<Element> &
KPBag<Element>::add(const KPBag<Element> &bag)
{
KPIterator<KPBag<Element>::Slot> a(my_list);
KPReadOnlyIterator<KPBag<Element>::Slot> b(bag.my_list);
while (b.ptr()) {
while (a.ptr() && a->my_element < b->my_element)
a++;
if (!a.ptr()) {
for (; b.ptr(); b++)
my_list.add_to_tail(*b);
}
else {
if (a->my_element == b->my_element) {
a->my_count += b->my_count;
a++;
}
else
a.insert_before_current(*b);
b++;
}
}
return *this;
}
/****************************************************************************/
template <class Element>
KPBag<Element> &
KPBag<Element>::add(const Element &element, int num)
{
if (num < 0) {
cerr << "KPBag - can't add a negative number of something\n";
exit(EXIT_FAILURE);
}
else if (num > 0) {
KPIterator<KPBag<Element>::Slot> iter(my_list);
// Start looking from the end of the list, in case the elements are
// being added in alphabetical order.
iter.end();
while (iter.ptr() && element < iter->my_element)
--iter;
if (!iter.ptr()) {
KPBag<Element>::Slot slot(element, num);
my_list.add_to_head(slot);
}
else if (iter->my_element == element)
iter->my_count += num;
else {
KPBag<Element>::Slot slot(element, num);
iter.insert_after_current(slot);
}
}
return *this;
}
/****************************************************************************/
template <class Element>
KPBag<Element>
KPBag<Element>::operator-(const KPBag<Element> &bag) const
{
KPBag<Element> new_bag;
KPReadOnlyIterator<KPBag<Element>::Slot> a(my_list), b(bag.my_list);
FOREACH(b) {
while (a.ptr() && a->my_element < b->my_element)
a++;
if (!a.ptr() || b->my_element < a->my_element ||
b->my_count > a->my_count) {
cerr << "KPBag - error subtracting more than exists\n";
exit(EXIT_FAILURE);
}
else if (b->my_count < a->my_count) {
KPBag<Element>::Slot slot(a->my_element, a->my_count - b->my_count);
new_bag.my_list.add_to_tail(slot);
}
a++;
}
return new_bag;
}
/****************************************************************************/
template <class Element>
inline KPBag<Element>
KPBag<Element>::operator-(const Element &element) const
{
KPBag<Element> new_bag(*this);
return new_bag.remove(element, 1);
}
/****************************************************************************/
template <class Element>
inline KPBag<Element> &
KPBag<Element>::operator-=(const KPBag<Element> &bag)
{
return remove(bag);
}
/****************************************************************************/
template <class Element>
inline KPBag<Element> &
KPBag<Element>::operator-=(const Element &element)
{
return remove(element, 1);
}
/****************************************************************************/
template <class Element>
KPBag<Element> &
KPBag<Element>::remove(const KPBag &bag)
{
if (this == &bag)
my_list.clear();
else {
KPIterator<KPBag<Element>::Slot> a(my_list);
KPReadOnlyIterator<KPBag<Element>::Slot> b(bag.my_list);
FOREACH(b) {
while (a.ptr() && a->my_element < b->my_element)
a++;
if (!a.ptr() || b->my_element < a->my_element ||
b->my_count > a->my_count) {
cerr << "KPBag - error subtracting more than exists\n";
exit(EXIT_FAILURE);
}
else if (b->my_count < a->my_count)
a->my_count -= b->my_count;
else
a.remove_current();
a++;
}
}
return *this;
}
/****************************************************************************/
template <class Element>
KPBag<Element> &
KPBag<Element>::remove(const Element &element, int num)
{
KPIterator<KPBag<Element>::Slot> iter(my_list);
while (iter.ptr() && iter->my_element < element)
iter++;
if (!iter.ptr() || element < iter->my_element || num > iter->my_count) {
cerr << "KPBag - error subtracting more than exists\n";
exit(EXIT_FAILURE);
}
else if (num < iter->my_count)
iter->my_count -= num;
else
iter.remove_current();
return *this;
}
/****************************************************************************/
template <class Element>
KPBag<Element> &
KPBag<Element>::remove_all(const Element &element)
{
KPIterator<KPBag<Element>::Slot> iter(my_list);
while (iter.ptr() && iter->my_element < element)
iter++;
if (iter.ptr() && iter->my_element == element)
iter.remove_current();
return *this;
}
/****************************************************************************/
template <class Element>
bool
KPBag<Element>::operator==(const KPBag<Element> &bag) const
{
if (this == &bag)
return true;
if (my_list.size() != bag.my_list.size())
return false;
KPReadOnlyIterator<KPBag<Element>::Slot> a(my_list), b(bag.my_list);
while (a.ptr()) {
if (!(a->my_count == b->my_count && a->my_element == b->my_element))
return false;
a++, b++;
}
return true;
}
/****************************************************************************/
template <class Element>
inline bool
KPBag<Element>::operator!=(const KPBag<Element> &bag) const
{
return !operator==(bag);
}
/****************************************************************************/
template <class Element>
bool
KPBag<Element>::operator<(const KPBag<Element> &bag) const
{
if (bag.my_list.size() < my_list.size())
return false;
else if (my_list.size() < bag.my_list.size())
return true;
else {
KPReadOnlyIterator<KPBag<Element>::Slot> a(my_list), b(bag.my_list);
while (a.ptr()) {
if (b->my_count < a->my_count)
return false;
else if (a->my_count < b->my_count)
return true;
else if (b->my_element < a->my_element)
return false;
else if (a->my_element < b->my_element)
return true;
a++, b++;
}
}
return false;
}
/****************************************************************************/
template <class Element>
inline KPBag<Element> &
KPBag<Element>::operator=(const KPBag<Element> &bag)
{
my_list = bag.my_list;
return *this;
}
/****************************************************************************/
template <class Element>
inline KPBag<Element> &
KPBag<Element>::operator=(const Element &element)
{
KPBag<Element>::Slot slot(element, 1);
my_list += slot;
return *this;
}
/****************************************************************************/
template <class Element>
KPBag<Element> &
KPBag<Element>::operator=(const KPList<Element> &list)
{
clear();
KPReadOnlyIterator<Element> iter(list);
FOREACH(iter)
add(*iter);
return *this;
}
/****************************************************************************/
template <class Element>
KPList<Element>
KPBag<Element>::list() const
{
KPList<Element> list;
KPReadOnlyIterator<KPBag<Element>::Slot> iter(my_list);
FOREACH(iter)
for (register int i=0; i<iter->my_count; i++)
list.add_to_tail(iter->my_element);
return list;
}
/****************************************************************************/
template <class Element>
KPList<Element>
KPBag<Element>::unique_list() const
{
KPList<Element> list;
KPReadOnlyIterator<KPBag<Element>::Slot> iter(my_list);
FOREACH(iter)
list.add_to_tail(iter->my_element);
return list;
}
/****************************************************************************/
template <class Element>
int
KPBag<Element>::size() const
{
int total_count = 0;
KPReadOnlyIterator<KPBag<Element>::Slot> iter(my_list);
FOREACH(iter)
total_count += iter->my_count;
return total_count;
}
/****************************************************************************/
template <class Element>
inline int
KPBag<Element>::unique_size() const
{
return my_list.size();
}
/****************************************************************************/
template <class Element>
inline bool
KPBag<Element>::is_empty() const
{
return my_list.is_empty();
}
/****************************************************************************/
template <class Element>
bool
KPBag<Element>::contains(const KPBag<Element> &bag) const
{
if (this == &bag)
return true;
KPReadOnlyIterator<KPBag<Element>::Slot> a(my_list), b(bag.my_list);
while (b.ptr()) {
while (a.ptr() && a->my_element < b->my_element)
a++;
if (!(a.ptr() && a->my_element == b->my_element &&
a->my_count >= b->my_count))
return false;
a++;
b++;
}
return true;
}
/****************************************************************************/
template <class Element>
bool
KPBag<Element>::contains(const Element &element, int num) const
{
KPReadOnlyIterator<KPBag<Element>::Slot> iter(my_list);
while (iter.ptr() && iter->my_element < element)
iter++;
return (iter.ptr() && iter->my_element == element && iter->my_count >= num);
}
/****************************************************************************/
template <class Element>
int
KPBag<Element>::occurrences_of(const Element &element) const
{
KPReadOnlyIterator<KPBag<Element>::Slot> iter(my_list);
while (iter.ptr() && iter->my_element < element)
iter++;
if (iter.ptr() && iter->my_element == element)
return iter->my_count;
else
return 0;
}
/****************************************************************************/
template <class Element>
Element
KPBag<Element>::retrieve()
{
if (my_list.is_empty()) {
cerr << "KPBag: retreive() - bag empty\n";
exit(EXIT_FAILURE);
}
Element element = my_list.head().my_element;
if (--my_list.head().my_count == 0)
my_list.remove_head();
return element;
}
/****************************************************************************/
template <class Element>
inline KPBag<Element> &
KPBag<Element>::clear()
{
my_list.clear();
return *this;
}
/****************************************************************************/
#endif /* KP_BAG_DEFINED */